/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.util;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author rufersic
 */
public class Automata {

    private int estado_inicial;
//    private String[] Conjunto_alfabeto;
//    private int[] Conjunto_estados;
//    private int[] Estados_finales;
//    private String[] Conjunto_trasiciones;
    private List<String> Conjunto_alfabeto;
    private List<Integer> Conjunto_estados;
    private List<Integer> Estados_finales;
    private List<String> Conjunto_trasiciones;
    private boolean tipo;

    /*datos de entrada para el metodo:
     *resive un automata
     *necesitamos generar 4 listas: una que nos almacene los conjuntos 
     generados por cada  funcion mover a los cuales se  les ralizara la cerradura exilon.
     Esta estructura(la primera lista ) nos servira como una pila, ya que ira eliminando el elemento 1 de el array
     la llamaremos L_C
     *la segunda lista es parecida a la primera, a diferencia de que no elimina elementos
     su funcion es permitirnos validar que no se les realice la funcion cerradura a conjutnos que ya se les realizo dicha funcion
     es como si controlara que no se repitan elementos
     A esta lista la llamaremos l_c_k
     *la tercera lista cumple la funcion de ser un contenedor de conjuntos.
     Un conjunto es una agrupacion de elementos(estados) que tiene  un nombre ejemplo A={1,2,3,4}
     A esta lista la llamaremos L_E 
     *nuestra ultima lista tiene como funcion controlar que no serepita  la funcion cerradura_exilon a conjuntos 
     a los cuales ya se le calculo la funcion.
     la llamaremos l_e_aux
    
     */
    //el siguiente metodo nos permite saber se existe un elemento dentro de una lista de conjuntos
    //(!l_e_aux.contains(l_C.get(0)))
    public static boolean siExisteElElemento(List<Conjunto> l, Conjunto c) {
        for (Conjunto conj : l) {
            if (conj.getElementos().equals(c.getElementos())) {
                return true;
            }
        }
        return false;
    }

    public Automata convertirAFNaAFD(Automata automata) {
        Automata a_determinista = new Automata();
        List<Conjunto> l_C = new ArrayList<>();
        List<Conjunto> l_C_k = new ArrayList<>();
        List<Conjunto> l_E = new ArrayList<>();
        List<Conjunto> l_e_aux = new ArrayList<>();

        Conjunto otros_conjuntos = new Conjunto();
        boolean primeravez = true;
        //
        int k = 0;
        
        List<Dato> dto = new ArrayList<>();
        
        int aux = -1;
        //
        List<Integer> arraydeunsoloelemento = new ArrayList<>();
        //mientras la lista de conjuntos mover no este vacia o sea la primera vez
        while (primeravez || !l_C.isEmpty()) {
            if (primeravez) {
                Conjunto c = new Conjunto();
                //guardamos el primer estado del automata
                arraydeunsoloelemento.add(automata.getEstado_inicial());
                otros_conjuntos.setElementos(arraydeunsoloelemento);
                l_e_aux.add(otros_conjuntos);
                Conjunto get = l_e_aux.get(0);
                List<Integer> vector = new ArrayList<>();
                for (int i : get.getElementos()) {
                    vector.add(i);
                }
                List<Integer> elementos_cerradura = cerraduraE(vector);
                c.setElementos(elementos_cerradura);
                aux++;
                c.setNumero(aux);
                l_E.add(c);
                //la funcion mover se realiza para cada elemento de el alfabeto
                for (String s : getConjunto_alfabeto()) {
                    String str = "";
                    str = "" + k + "," + s + ",";
                    Dato d = new Dato();
                    d.setCadena(str);
                    List<Integer> mov = mover(c, s);
                    d.setListaenteros(mov);
                    dto.add(d);
                    

                    Conjunto c2 = new Conjunto();
                    c2.setElementos(mov);

                    if (!l_C_k.isEmpty()) {
                        if (!siExisteElElemento(l_C_k, c2)) {
                            l_C_k.add(c2);
                            l_C.add(c2);
                        }
                    } else {
                        l_C_k.add(c2);
                        l_C.add(c2);

                    }
                }
                k++;
                primeravez = false;
            } else {
                Conjunto c = new Conjunto();
                //preguntamos si el resultado de una funcion mover se encuentra en  la lista de parametros que entran en la funcion exilon
                boolean sw2 = siExisteElElemento(l_e_aux, l_C.get(0));

                if (!sw2) {
                    //si no se encuentra lo almacenamos
                    l_e_aux.add(l_C.get(l_C.size() - 1));
                    //generamos un nuuevo conjunto y lo guardamos en la lista de conjuntos generados por cerradura_e

                    c.setElementos(cerraduraE(l_C.get(l_C.size() - 1).getElementos()));
                    aux++;
                    c.setNumero(aux);
                    l_E.add(c);
                    for (String s : getConjunto_alfabeto()) {
                        String str = "";
                        str = "" + k + "," + s + ",";
                        Dato d = new Dato();
                        d.setCadena(str);
                        List<Integer> mov = mover(c, s);
                        Conjunto c2 = new Conjunto();
                        c2.setElementos(mov);
                        d.setListaenteros(mov);
                        dto.add(d);
                        

                        if (!siExisteElElemento(l_C_k, c2)) {
                            l_C_k.add(c2);
                            l_C.add(c2);
                        }
                    }
                    k++;
                    l_C.remove(0);
                }
            }
        }
        //falta probar y genera las nuevas transiciones
        List<Integer> estasdos = new ArrayList<>();
        List<Integer> estadosfinales = new ArrayList<>();
        a_determinista.setConjunto_alfabeto(Conjunto_alfabeto);
        for (int i = 0; i < l_E.size(); i++) {
            estasdos.add(i);
        }
        a_determinista.setConjunto_estados(estasdos);
        a_determinista.setEstado_inicial(0);
        int j = 0;
        int estadofinal = Estados_finales.get(j);
        for (Conjunto cjtoo : l_E) {
            for (int i = 0; i < cjtoo.getElementos().size(); i++) {
                if (cjtoo.getElementos().get(i) == estadofinal) {
                    estadosfinales.add(i);
                    break;
                }
            }
            j++;
        }
        a_determinista.setEstados_finales(estadosfinales);
        //agregamos las trasiciones
        List<String>trasicionesfeinales=new ArrayList<>();
        for(Dato d: dto){
         List<Integer> l = d.getListaenteros();    
        for(int i=0;i<l_E.size();i++){
         List<Integer>l2= l_E.get(i).getElementos();
         if(l.equals(l2)){
         String cadena=""+d.getCadena()+l_E.get(i).getNumero();
         trasicionesfeinales.add(cadena);
         break;
         }
        }
        }
        a_determinista.setConjunto_trasiciones(trasicionesfeinales);
        //aqui generamos el nuevo automata
        EscribirXml.generarXml(a_determinista);
        return a_determinista;
    }

    //verificar si la lista contiene una  transcicion con el estado final de la trancicions recibida
    public List<Integer> cerraduraE(List<Integer> list) {
        List<Integer> list1 = new ArrayList<>();
        list1.addAll(list);
        //creamos la lista que contendra la cadena exilon
        List<Integer> listE = new ArrayList<>();
        //creamos una lista temporal
        List<Integer> temp = new ArrayList<>();
        //creamos un sw
        boolean sw = false;
        //le cambie el <= por un <
        for (int i = 0; i < list.size(); i++) {
            while (!temp.isEmpty() || !sw) {
                //hacemos sw=true para que entre por primera vez, y despues el cierre de el ciclo dependa 
                //totalmente de que temp este vacia
                sw = true;
                //resivo el estado i y lo almaceeno en la lista temporal
                //pero antes verifico que no se repita
                if (!temp.contains(list1.get(i))) {
                    temp.add(list1.get(i));
                }
                //añado el estado de la lista temp en la posicion 0 a la lista de exilon    
                listE.add(temp.get(0));
                //ahora buscamos en la lista de trasiciones a quellas trasiciones que comiencen con el estado resivido
                //y tengan un exilon #
                //verificamos que no se repitan
                //y añadimos esas trasiciones a la lista temp
                for (String s : getConjunto_trasiciones()) {
                    if ((s.indexOf("#") >= 0) && (s.indexOf(list1.get(i).toString()) >= 0)) {
                        if (!temp.contains(Integer.parseInt(s.charAt(4) + ""))) {
                            temp.add(Integer.parseInt(s.charAt(4) + ""));
                        }
                        temp.remove(0);
                    }
                }
                temp.remove(0);
            }
            sw = false;
        }

        return listE;

    }

    public List<Integer> mover(Conjunto c, String elemento_alfabeto) {
        List<Integer> resultado_mover = new ArrayList<>();
        for (int i = 0; i < c.getElementos().size(); i++) {
            for (String s : Conjunto_trasiciones) {
                List<Integer> element = c.getElementos();
                if (Integer.parseInt("" + s.charAt(0)) == element.get(i) && ("" + s.charAt(2)).equals(elemento_alfabeto)) {
                    resultado_mover.add(Integer.parseInt(s.charAt(4) + ""));
                }
            }
        }
        return resultado_mover;
    }

//    
    /**
     * @return the estado_inicial
     */
    public int getEstado_inicial() {
        return estado_inicial;
    }

    /**
     * @param estado_inicial the estado_inicial to set
     */
    public void setEstado_inicial(int estado_inicial) {
        this.estado_inicial = estado_inicial;
    }

    /**
     * @return the tipo
     */
    public boolean isTipo() {
        return tipo;
    }

    /**
     * @param tipo the tipo to set
     */
    public void setTipo(boolean tipo) {
        this.tipo = tipo;
    }

    /**
     * @return the Conjunto_alfabeto
     */
    public List<String> getConjunto_alfabeto() {
        return Conjunto_alfabeto;
    }

    /**
     * @param Conjunto_alfabeto the Conjunto_alfabeto to set
     */
    public void setConjunto_alfabeto(List<String> Conjunto_alfabeto) {
        this.Conjunto_alfabeto = Conjunto_alfabeto;
    }

    /**
     * @return the Conjunto_estados
     */
    public List<Integer> getConjunto_estados() {
        return Conjunto_estados;
    }

    /**
     * @param Conjunto_estados the Conjunto_estados to set
     */
    public void setConjunto_estados(List<Integer> Conjunto_estados) {
        this.Conjunto_estados = Conjunto_estados;
    }

    /**
     * @return the Estados_finales
     */
    public List<Integer> getEstados_finales() {
        return Estados_finales;
    }

    /**
     * @param Estados_finales the Estados_finales to set
     */
    public void setEstados_finales(List<Integer> Estados_finales) {
        this.Estados_finales = Estados_finales;
    }

    /**
     * @return the Conjunto_trasiciones
     */
    public List<String> getConjunto_trasiciones() {
        return Conjunto_trasiciones;
    }

    /**
     * @param Conjunto_trasiciones the Conjunto_trasiciones to set
     */
    public void setConjunto_trasiciones(List<String> Conjunto_trasiciones) {
        this.Conjunto_trasiciones = Conjunto_trasiciones;
    }
    /**
     * @return the estado_inicial
     */
}
